
`include "arbitre.v"
`include "constantes.v" 

module bus(
	clk,
	reset,
	FeSys_Req,
	CaSys_Req,
	WBSys_Req,
	HDSys_Req,
	
	CaSys_ACK,
	FeSys_ACK,
	MemSys_ACK,
	HDSys_ACK,
	
	WB_Data_O,
	HD_Data_O,
	Ca_Data_I,

	Mem_Data_I,
	FeSys_Adr,
	CaSys_Adr,
	WBSys_Adr,
	HDSys_Adr,	
	
	FeSys_Ctl,
	CaSys_Ctl,
	WBSys_Ctl,
	HDSys_Ctl,
	
	SysFe_Gnt,
	SysCa_Gnt,
	SysHD_Gnt,
	SysWB_Gnt,
	Bus_Gnt,
	
	Bus_Data_I,
	Bus_Data_O,
	Bus_Adr,
	Bus_Ctl,
	Bus_ACK,
);

// Declaracion tipos datos
input					clk;
input					reset;
input					FeSys_Req;
input 					CaSys_Req;
input					WBSys_Req;
input					HDSys_Req;
input 					CaSys_ACK;
input					MemSys_ACK;
input					HDSys_ACK; 
input					FeSys_ACK;
input [`TAM_BDAT:0]		WB_Data_O;
input [`TAM_BDAT:0]		HD_Data_O;
input [`TAM_BDAT:0]		Ca_Data_I;
input [`TAM_BDAT:0]		Mem_Data_I;
input [`TAM_BADR:0] 	FeSys_Adr;
input [`TAM_BADR:0] 	CaSys_Adr;
input [`TAM_BADR:0]		WBSys_Adr;
input [`TAM_BADR:0]		HDSys_Adr;
input [`TAM_BCTL:0] 	FeSys_Ctl;
input [`TAM_BCTL:0] 	CaSys_Ctl;
input [`TAM_BCTL:0]		WBSys_Ctl;
input [`TAM_BCTL:0]		HDSys_Ctl;	

output					SysFe_Gnt;
output					SysCa_Gnt;
output					SysHD_Gnt;
output					SysWB_Gnt;
output					Bus_Gnt;
output [`TAM_BDAT:0]	Bus_Data_I;
output [`TAM_BDAT:0]	Bus_Data_O;
output [`TAM_BADR:0]	Bus_Adr;
output [`TAM_BCTL:0]	Bus_Ctl;
output					Bus_ACK;

reg 					SysFe_Gnt;
reg						SysCa_Gnt;
reg						SysHD_Gnt;
reg						SysWB_Gnt;
reg						Bus_Gnt;
reg [`TAM_BDAT:0]		Bus_Data_I;
reg [`TAM_BDAT:0]		Bus_Data_O;
reg [`TAM_BADR:0]		Bus_Adr;
reg [`TAM_BCTL:0]		Bus_Ctl;
wire					Bus_ACK;

// Registros internos   
																	  
wire		FeAr_Req;
wire		CaAr_Req;
wire		WBAr_Req;
wire		HDAr_Req;
wire		ACK;
wire		Gnt;
wire		ArFe_Gnt;
wire		ArCa_Gnt;
wire		ArWB_Gnt;
wire		ArHD_Gnt;

// programa
assign	FeAr_Req = FeSys_Req;
assign	CaAr_Req = CaSys_Req;
assign	WBAr_Req = WBSys_Req;
assign	HDAr_Req = HDSys_Req;				  

assign Bus_ACK = (MemSys_ACK || HDSys_ACK || CaSys_ACK);	

				 			 
always@ (posedge clk) begin					  
	if (ArWB_Gnt == 1 && WBSys_Req == 1) begin 
		SysFe_Gnt = 0;							 
		SysCa_Gnt = 0;
		SysWB_Gnt = 1;
		SysHD_Gnt = 0;
		//Bus_Gnt = 1;
	end else if (ArCa_Gnt == 1 && CaSys_Req == 1) begin
		SysFe_Gnt = 0;
		SysCa_Gnt = 1;
		SysWB_Gnt = 0;
		SysHD_Gnt = 0;
		//Bus_Gnt = 1;
	end else if (ArFe_Gnt == 1 && FeSys_Req == 1) begin
		SysFe_Gnt = 1;
		SysCa_Gnt = 0;
		SysWB_Gnt = 0;
		SysHD_Gnt = 0;
		//Bus_Gnt = 1;
	end else if (ArHD_Gnt == 1 && HDSys_Req == 1) begin
		SysFe_Gnt = 0;
		SysCa_Gnt = 0;
		SysWB_Gnt = 0;	
		SysHD_Gnt = 1;
		//Bus_Gnt = 1;
	end else begin
		Bus_Gnt = 0;  
	    SysFe_Gnt = 0;
		SysCa_Gnt = 0;
		SysWB_Gnt = 0;
		SysHD_Gnt = 0;
		SysFe_Gnt = ArFe_Gnt;
		SysCa_Gnt = ArCa_Gnt;
		SysWB_Gnt = ArWB_Gnt;
		SysHD_Gnt = ArHD_Gnt;
		Bus_Gnt = Gnt;
	end
end	  

// Multiplesor d'entrada a los buses
always @ (posedge clk)
begin			  
  	if (SysWB_Gnt) begin	
		  
	   	Bus_Data_O 	= WB_Data_O;
	    Bus_Adr	= WBSys_Adr;
	    Bus_Ctl	= WBSys_Ctl;	 
		
	end else if (SysCa_Gnt) begin
		
		Bus_Adr	= CaSys_Adr;
		Bus_Ctl	= CaSys_Ctl;	  
		
	end else if (SysFe_Gnt) begin
		
		//if (FeSys_ACK) begin
			Bus_Adr	= FeSys_Adr;
			Bus_Ctl	= FeSys_Ctl;
			Bus_Gnt = 1;
		//end
		
	end else if (SysHD_Gnt) begin	
		
	    Bus_Data_O 	= HD_Data_O;
	    Bus_Adr	= HDSys_Adr;
	    Bus_Ctl	= HDSys_Ctl;	
		
	end
	//if (Bus_Ctl == `READ_MASK) begin
		//Bus_Data_O = Ca_Data_I;				
	//end else
	if (SysCa_Gnt) begin
		if(Bus_Ctl == `READ_MASK)begin 
			Bus_Data_O = Ca_Data_I;
		end else begin
			Bus_Data_I	= Mem_Data_I;
		end
	end else if (SysFe_Gnt) begin
		Bus_Data_I	= Mem_Data_I;
	end else if (SysHD_Gnt) begin
	    Bus_Data_I	= Mem_Data_I;
	end	 
end

// Connexion con el arbitre

arbitre UI (
.clk (clk),
.reset (reset),
.FeAr_Req (FeAr_Req),
.CaAr_Req (CaAr_Req),
.WBAr_Req (WBAr_Req),
.HDAr_Req (HDAr_Req),
.ArFe_Gnt (ArFe_Gnt),
.ArCa_Gnt (ArCa_Gnt),
.ArWB_Gnt (ArWB_Gnt),
.ArHD_Gnt (ArHD_Gnt),
.Gnt(Gnt)
);

endmodule

